home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 July / EnigmA AMIGA RUN 20 (1997)(G.R. Edizioni)(IT)[!][issue 1997-07 & 08][EAR-CD IV].iso / earcd / game / text / lists.lha / listsdir / lists-manual.inf next >
Text File  |  1996-12-06  |  62KB  |  1,662 lines

  1.  
  2. [ print_title str;
  3.     style bold;
  4.     print (string) str;
  5.     style roman;
  6.     new_line; new_line;
  7. ];
  8.  
  9. ! in arguments, 1 means blank line; 2 means skip entirely
  10. [ print_trans inpstr outstr;
  11.     !font off;
  12.     if (inpstr ~= 2) {
  13.         print " >>";
  14.         if (inpstr ~= 1) {
  15.             style bold;
  16.             print (string) inpstr;
  17.             style roman;
  18.         }
  19.         new_line;
  20.     }
  21.     if (outstr ~= 2) {
  22.         if (outstr ~= 1) {
  23.             print " ", (string) outstr;
  24.         }
  25.         new_line;
  26.     }
  27.     !font on;
  28. ];
  29.  
  30. [ print_multiatom a1 a2 a3 a4 a5 a6 a7 a8;
  31.     style bold;
  32.     if (a1 ~= 0)
  33.         print (string) a1, "^";
  34.     if (a2 ~= 0)
  35.         print (string) a2, "^";
  36.     if (a3 ~= 0)
  37.         print (string) a3, "^";
  38.     if (a4 ~= 0)
  39.         print (string) a4, "^";
  40.     if (a5 ~= 0)
  41.         print (string) a5, "^";
  42.     if (a6 ~= 0)
  43.         print (string) a6, "^";
  44.     if (a7 ~= 0)
  45.         print (string) a7, "^";
  46.     if (a8 ~= 0)
  47.         print (string) a8, "^";
  48.     style roman;
  49. ];
  50.  
  51. [ print_multitrans a1 a2 a3 a4 a5 a6 a7 a8;
  52.     print " >>";
  53.     style bold; print (string) a1; style roman; new_line;
  54.     if (a2 == 0)
  55.         return;
  56.     print "  >";
  57.     style bold; print (string) a2; style roman; new_line;
  58.     if (a3 == 0)
  59.         return;
  60.     print "  >";
  61.     style bold; print (string) a3; style roman; new_line;
  62.     if (a4 == 0)
  63.         return;
  64.     print "  >";
  65.     style bold; print (string) a4; style roman; new_line;
  66.     if (a5 == 0)
  67.         return;
  68.     print "  >";
  69.     style bold; print (string) a5; style roman; new_line;
  70.     if (a6 == 0)
  71.         return;
  72.     print "  >";
  73.     style bold; print (string) a6; style roman; new_line;
  74.     if (a7 == 0)
  75.         return;
  76.     print "  >";
  77.     style bold; print (string) a7; style roman; new_line;
  78.     if (a8 == 0)
  79.         return;
  80.     print "  >";
  81.     style bold; print (string) a8; style roman; new_line;
  82.     
  83.     return;
  84. ];
  85.  
  86. [ print_moretrans a1 a2 a3 a4 a5 a6 a7 a8;
  87.     print "  >";
  88.     style bold; print (string) a1; style roman; new_line;
  89.     if (a2 == 0)
  90.         return;
  91.     print "  >";
  92.     style bold; print (string) a2; style roman; new_line;
  93.     if (a3 == 0)
  94.         return;
  95.     print "  >";
  96.     style bold; print (string) a3; style roman; new_line;
  97.     if (a4 == 0)
  98.         return;
  99.     print "  >";
  100.     style bold; print (string) a4; style roman; new_line;
  101.     if (a5 == 0)
  102.         return;
  103.     print "  >";
  104.     style bold; print (string) a5; style roman; new_line;
  105.     if (a6 == 0)
  106.         return;
  107.     print "  >";
  108.     style bold; print (string) a6; style roman; new_line;
  109.     if (a7 == 0)
  110.         return;
  111.     print "  >";
  112.     style bold; print (string) a7; style roman; new_line;
  113.     if (a8 == 0)
  114.         return;
  115.     print "  >";
  116.     style bold; print (string) a8; style roman; new_line;
  117.     
  118.     return;
  119. ];
  120.  
  121. Constant ManualContents "Table of Contents:^\
  122.         ^    0:  Introduction\
  123.         ^    1:  What's Going On Here\
  124.         ^    2:  What's An Atom?\
  125.         ^    3:  What's a List?\
  126.         ^    4:  Functions\
  127.         ^    5:  Quoting Expressions\
  128.         ^    6:  Defining Atoms\
  129.         ^    7:  List Chopping\
  130.         ^    8:  List Constructing\
  131.         ^    9:  Tests and Logic\
  132.         ^    10: Comparisons\
  133.         ^    11: Conditionals\
  134.         ^    12: Creating Functions\
  135.         ^    13: Fun With Recursion\
  136.         ^    14: Local Definitions With Let\
  137.         ^    15: Recursion, Functions, Endless Fun\
  138.         ^    16: Scope\
  139.         ^    17: Return\
  140.         ^    18: Reference: Functions\
  141.         ^    19: Reference: Syntactic Forms\
  142.         ^    20: Reference: Improper Lists^";
  143.  
  144. [ EnterManual;
  145.     DoMenu(#r$PrintManualContents, #r$ManualMenu, #r$ManualEntry);
  146. ];
  147.  
  148. ! Assumes we're set to the status window
  149. [ PrintManualContents
  150.     wid lines i j k;
  151.     
  152.     wid = 0->33;
  153.     if (wid==0) i=80;
  154.     lines = 21;
  155.     
  156.     @set_cursor 5 2;
  157.     print "Table of Contents:";
  158.     
  159.     for (i=0 : i<lines : i++) {
  160.         menu_item = i+1;
  161.         ManualMenu();
  162.         if (i < lines/2) {
  163.             j = i+7;
  164.             k = 4;
  165.         }
  166.         else {
  167.             j = i-lines/2+7; 
  168.             k = wid/2+4;
  169.         }
  170.         k = k+1;
  171.         @set_cursor j k;
  172.         print (string) item_name;
  173.     }
  174. ];
  175.  
  176. [ ManualMenu;
  177.     if (menu_item == 0) {
  178.         item_name =     "A Simple Programmer's Introduction to Scheme";
  179.         item_width = 22;
  180.         return 21;
  181.     }
  182.     switch (menu_item-1) {
  183.         0:
  184.             item_name = "Introduction";
  185.             item_width = 6;
  186.         1:
  187.             item_name = "What's Going On Here";
  188.             item_width = 10;
  189.         2:
  190.             item_name = "What's An Atom?";
  191.             item_width = 7;
  192.         3:
  193.             item_name = "What's a List?";
  194.             item_width = 7;
  195.         4:
  196.             item_name = "Functions";
  197.             item_width = 4;
  198.         5:
  199.             item_name = "Quoting Expressions";
  200.             item_width = 9;
  201.         6:
  202.             item_name = "Defining Atoms";
  203.             item_width = 7;
  204.         7:
  205.             item_name = "List Chopping";
  206.             item_width = 6;
  207.         8:
  208.             item_name = "List Constructing";
  209.             item_width = 8;
  210.         9:
  211.             item_name = "Tests and Logic";
  212.             item_width = 7;
  213.         10:
  214.             item_name = "Comparisons";
  215.             item_width = 5;
  216.         11:
  217.             item_name = "Conditionals";
  218.             item_width = 6;
  219.         12:
  220.             item_name = "Creating Functions";
  221.             item_width = 9;
  222.         13:
  223.             item_name = "Fun With Recursion";
  224.             item_width = 9;
  225.         14:
  226.             item_name = "Local Definitions With Let";
  227.             item_width = 13;
  228.         15:
  229.             item_name = "Recursion, Functions";
  230.             item_width = 10;
  231.         16:
  232.             item_name = "Scope";
  233.             item_width = 2;
  234.         17:
  235.             item_name = "Return";
  236.             item_width = 3;
  237.         18:
  238.             item_name = "Reference: Functions";
  239.             item_width = 10;
  240.         19:
  241.             item_name = "Reference: Syntactic Forms";
  242.             item_width = 13;
  243.         20:
  244.             item_name = "Reference: Improper Lists";
  245.             item_width = 12;
  246.         default:
  247.             item_name = "ITEM";
  248.             item_width = 2;
  249.     }
  250.     rtrue;
  251. ];
  252.  
  253. [ ManualEntry;
  254.     PrintChapter(menu_item-1);
  255. ];
  256.  
  257. [ DoMenu menu_choices EntryR ChoiceR
  258.          lines main_title main_wid cl i j k oldcl pkey;
  259.   if (pretty_flag==0)
  260.   {   LowKey_Menu(menu_choices,EntryR,ChoiceR);
  261.       rfalse;
  262.   }
  263.   menu_nesting++;
  264.   menu_item=0;
  265.   lines=indirect(EntryR);
  266.   main_title=item_name; main_wid=item_width;
  267.   cl=0;
  268.   .ReDisplay;
  269.       oldcl=-1;
  270.       @erase_window $ffff;
  271.       i=(lines+1)/2+7;
  272.       @split_window i;
  273.       i = 0->33;
  274.       if (i==0) i=80;
  275.       @set_window 1;
  276.       @set_cursor 1 1;
  277.       style reverse;
  278.       spaces(i); j=i/2-main_wid;
  279.       @set_cursor 1 j;
  280.       print_paddr main_title;
  281.       @set_cursor 2 1; spaces(i);
  282.       @set_cursor 2 2; print "N = next subject";
  283.       j=i-12; @set_cursor 2 j; print "P = previous";
  284.       @set_cursor 3 1; spaces(i);
  285.       @set_cursor 3 2; print "RETURN = read subject";
  286.       j=i-17; @set_cursor 3 j;
  287.       if (menu_nesting==1)
  288.           print "  Q = resume game";
  289.       else
  290.           print "Q = previous menu";
  291.       style roman;
  292.       @set_cursor 5 2; font off;
  293.  
  294.       if (ZRegion(menu_choices)==3) print_paddr menu_choices;
  295.       else indirect(menu_choices);
  296.  
  297.       .KeyLoop;
  298.       if (cl~=oldcl)
  299.       {   if (oldcl>=0) { 
  300.                if (oldcl < lines/2) {
  301.                    j = oldcl+7;
  302.                    k = 4;
  303.                }
  304.                else {
  305.                    j = oldcl-lines/2+7; 
  306.                    k = i/2+4;
  307.                }
  308.                @set_cursor j k; print " "; 
  309.           }
  310.           if (cl < lines/2) {
  311.               j = cl+7;
  312.               k = 4;
  313.           }
  314.           else {
  315.               j = cl-lines/2+7; 
  316.               k = i/2+4;
  317.           }
  318.           @set_cursor j k; 
  319.           print ">";
  320.       }
  321.       oldcl=cl;
  322.       @read_char 1 0 0 pkey;
  323.       if (pkey=='N' or 'n' or 130)
  324.           { cl++; if (cl>=lines) cl=0; jump KeyLoop; }
  325.       if (pkey=='P' or 'p' or 129)
  326.           { cl--; if (cl<0)  cl=lines-1; jump KeyLoop; }
  327.       if (pkey=='Q' or 'q' or 27) { jump QuitHelp; }
  328.       if (pkey==10 or 13)
  329.       {   @set_window 0; font on;
  330.           new_line; new_line; new_line;
  331.  
  332.           menu_item=cl+1;
  333.           indirect(EntryR);
  334.  
  335.           @erase_window $ffff;
  336.           @split_window 1;
  337.           i = 0->33; if (i==0) { i=80; }
  338.           @set_window 1; @set_cursor 1 1; style reverse; spaces(i);
  339.           j=i/2-item_width;
  340.           @set_cursor 1 j;
  341.           print_paddr item_name;
  342.           style roman; @set_window 0; new_line;
  343.  
  344.           i = indirect(ChoiceR);
  345.           if (i==2) jump ReDisplay;
  346.           if (i==3) jump QuitHelp;
  347.  
  348.           print "^[Please press SPACE.]^";
  349.           @read_char 1 0 0 pkey; jump ReDisplay;
  350.       }
  351.       jump KeyLoop;
  352.       .QuitHelp;
  353.       menu_nesting--; if (menu_nesting>0) rfalse;
  354.       font on; @set_cursor 1 1;
  355.       @erase_window $ffff; @set_window 0;
  356.       new_line; new_line; new_line;
  357.       ! if (deadflag==0) <<Look>>;
  358. ];  
  359.  
  360. [ PrintChapter num;
  361.     switch (num) {
  362.         0: Chapter0();
  363.         1: Chapter1();
  364.         2: Chapter2();
  365.         3: Chapter3();
  366.         4: Chapter4();
  367.         5: Chapter5();
  368.         6: Chapter6();
  369.         7: Chapter7();
  370.         8: Chapter8();
  371.         9: Chapter9();
  372.         10: Chapter10();
  373.         11: Chapter11();
  374.         12: Chapter12();
  375.         13: Chapter13();
  376.         14: Chapter14();
  377.         15: Chapter15();
  378.         16: Chapter16();
  379.         17: Chapter17();
  380.         18: Chapter18();
  381.         19: Chapter19();
  382.         20: Chapter20();
  383.     }
  384. ];
  385.  
  386. [ Chapter0;
  387.  
  388. print_title ("0. Introduction");
  389.  
  390. print (emphstring) "A Simple Programmer's Introduction to Scheme", "^^";
  391.  
  392. print "This is a story about Lisp. Actually -- I'll admit it right now -- it's about \
  393. Scheme, which is a cleaned-up version of Lisp. More suitable for teaching, \
  394. and (more to the point) easier for me to implement inside the Z-Machine. And -- \
  395. to be really honest -- I didn't implement much of Scheme either. But I think \
  396. it'll do for a start.^^";
  397.  
  398. print "Since you have the Scheme interpreter right underneath your fingers, your job \
  399. is to try all the examples. And experiment with new ones. Your friend the genie \
  400. will pose problems for you to solve, but it's all self-paced. Play around as \
  401. much as you want. Refer to this manual as much as you want. Or blow the whole \
  402. thing and go fight dragons. Will I care? (Sniff.)^^";
  403.  
  404. ];
  405.  
  406. [ Chapter1;
  407.  
  408. print_title ("1. What's Going On Here");
  409.  
  410. print "When you start the Scheme interpreter, you see a prompt:^^";
  411.  
  412. print_trans(1, 2);
  413. new_line;
  414.  
  415. print "You type things, and the interpreter responds. Try it. Type ~5~ and hit Enter. \
  416. The interpreter will respond with ~5~.^^";
  417.  
  418. print_trans(
  419.  "5",
  420.  "5"
  421. );
  422. new_line;
  423.  
  424. print "That's all that happens in Scheme. You can go home now. Bye!^^";
  425.  
  426. print "Ok, I'm kidding. Sort of. It's true, really -- all you do in Scheme is type \
  427. things, and get responses. The process is dynamic; the response can depend on \
  428. earlier things that you typed. Notice that this is different from languages \
  429. like C, or Pascal, or Inform. In those languages, you type in an entire \
  430. program, and chuck it into the compiler, which either grinds you out a program \
  431. or complains. In Scheme, or Lisp, you build programs out of small pieces. It's \
  432. much friendlier.^^";
  433.  
  434. print "But enough about Pascal. What happens in Scheme?^^";
  435.  
  436. print "What happens -- really -- is that you type an expression, and the interpreter \
  437. evaluates the expression and prints the result. Read, evaluate, print. Every \
  438. expression evaluates to another expression (unless it produces an error.) \
  439. We just demonstrated this; ", (atomstring) "5", " is an expression, and it evaluates \
  440. to the expression ", (atomstring) "5", ". Numbers evaluate to themselves. If that's confusing, \
  441. just try to get used to it. If it makes sense, you'll probably be confused \
  442. later on, because most expressions ", (emphstring) "don't", " evaluate to themselves. Oh well.^^";
  443.  
  444. ];
  445.  
  446. [ Chapter2;
  447.  
  448. print_title ("2. What's An Atom?");
  449.  
  450. print "We start with atoms.^^";
  451.  
  452. print "An atom is a bunch of characters. Letters, numbers, most punctuation. Here \
  453. are some atoms: ", (atomstring) "5", " ", (atomstring) "hello", " ", (atomstring) "-5", " ", (atomstring) "goodbye", " ", (atomstring) "darlene+mitchell", " ", (atomstring) "q-5", " ", (atomstring) "qq=5++qqq+", " ", (atomstring) "***", "^^";
  454.  
  455. print "If you're familiar with languages like Pascal, you're probably desperately \
  456. trying to read some of those as additions, or subtractions, or whatever. Don't \
  457. bother. They're all just atoms. Letters, numbers, and punctuation are all \
  458. treated the same in an atom.^^";
  459.  
  460. print "(For completeness, here's the list of punctuation which you ", (emphstring) "can't", " use in an \
  461. atom: ", (atomstring) "(", " ", (atomstring) ")", " ", (atomstring) ";", " ", (atomstring) ":", " ", (atomstring) "'", " ", (atomstring) ".", " Any kind of whitespace, such as spaces or line \
  462. breaks, will separate atoms as well.)^^";
  463.  
  464. print "So ho, you ask, what about numbers? Good point. An atom which is entirely made \
  465. up of numbers, except possibly for a minus sign at the front, counts as a number. \
  466. (Get it? Counts? Never mind.)^^";
  467.  
  468. print "We've already said that a number evaluates to itself. That is, if an expression \
  469. consists of just an atom, and the atom is a number, the value of that expression \
  470. is that very expression -- which is to say, that atom.^^";
  471.  
  472. print_trans("5",
  473.  "5");
  474. print_trans("-597",
  475.  "-597");
  476. print_trans("0",
  477.  "0");
  478. new_line;
  479.  
  480. print "What do other atoms evaluate to? Well, try it. I'll just cover my ears --^^";
  481.  
  482. print_trans("hello",
  483.  "[Error: undefined atom: hello]");
  484. print_trans("q-5",
  485.  "[Error: undefined atom: q-5]");
  486. print_trans("***",
  487.  "[Error: undefined atom: ***]");
  488. new_line;
  489.  
  490. print "Don't worry; no permanent damage done. Most non-numeric atoms produce errors when \
  491. you try to evaluate them. This is because they are not bound to any value. But \
  492. what that means, we'll get to later.^^";
  493.  
  494. ];
  495.  
  496. [ Chapter3;
  497.  
  498. print_title ("3. What's a List?");
  499.  
  500. print "A single atom is an expression. Is there any other kind of expression? Of course. \
  501. An expression can also be a list. One list -- that's important. An expression is \
  502. a single atom or a single list.^^";
  503.  
  504. print "What's a list? A list is a list of expressions. That is, a list is a list of atoms \
  505. and lists. A list is written as a pair of parentheses surrounding the contents of \
  506. the list. Here's a list: ", (atomstring) "(1)", " It contains one atom. Here's another list: ", (atomstring) "(2 fred)", " \
  507. It contains two atoms. The order is significant; ", (atomstring) "(2 fred)", " and ", (atomstring) "(fred 2)", " are two \
  508. different lists.^^";
  509.  
  510. print "A list can contain nothing: ", (atomstring) "()", " is the empty list. It's famous. It's also called \
  511. ", (atomstring) "nil", ", which I think isn't as pretty as ", (atomstring) "()", ", but it's historical, so there we are. \
  512. ", (atomstring) "nil", " and ", (atomstring) "()", " both refer to the empty list.^^";
  513.  
  514. print "As I said, a list can contain both atoms and other lists. So here are four more \
  515. lists: ", (atomstring) "(one (two) three)", " ", (atomstring) "(((one) 2 fred) xxxx9)", " ", (atomstring) "(())", " ", (atomstring) "(hello mr ((operator)))", " \
  516. Don't be frightened by the stacks of parentheses. It's all recursive. That last \
  517. list, for example, contains three expressions: the atom ", (atomstring) "hello", ", the atom ", (atomstring) "mr", ", and \
  518. the list ", (atomstring) "((operator))", ". Which, itself, is one-term list containing only the list \
  519. ", (atomstring) "(operator)", ". Which is, itself, a one-term list containing only the atom ", (atomstring) "operator", ". \
  520. Get it?^^";
  521.  
  522. print "By the way, remember that an expression is either a single atom or a single list. \
  523. ", (atomstring) "1", " ", (atomstring) "2", " ", (atomstring) "3", " is three separate expressions, not any funky kind of parenthesis-stripped \
  524. list or anything. If you type several expressions at the Scheme prompt, the \
  525. interpreter will evaluate them one at a time.^^";
  526.  
  527. print_trans("1 2 3 four",
  528.  "1");
  529. print_trans(2, "2");
  530. print_trans(2, "3");
  531. print_trans(2, "[Error: undefined atom: four]");
  532. new_line;
  533.  
  534. ];
  535.  
  536. [ Chapter4;
  537.  
  538. print_title ("4. Functions");
  539.  
  540. print "We've seen that numeric atoms evaluate to themselves, and other atoms seem to \
  541. produce raging error messages. What does a list evaluate to? Aha! You've heard of \
  542. functions? I really hope so. Anyway, when you evaluate a list, you're calling a \
  543. function. The first element of the list is the function; the rest of the elements \
  544. are its arguments.^^";
  545.  
  546. print_trans("(+ 1 1)",
  547.  "2");
  548. new_line;
  549.  
  550. print "Right! Addition! Let's take a closer look. We typed in an expression: \
  551. ", (atomstring) "(+ 1 1)", ". Nothing magic there; it's a list containing three atoms, of which \
  552. the first is a plus sign and the last two are both the number 1. The Scheme \
  553. interpreter evaluates all of these. The plus sign means addition; the ", (atomstring) "1", " atoms \
  554. both evaluate to themselves. So the interpreter runs the addition function, and \
  555. hands it a pair of ", (atomstring) "1", " atoms to work with. One plus one is two, so the function \
  556. returns the expression ", (atomstring) "2", ". And that's what ", (atomstring) "(+ 1 1)", " evaluates to.^^";
  557.  
  558. print "Sneaky people will raise their hands at this point. What am I trying to pull? \
  559. ~The plus sign means addition?~ Ok, ok. What I mean is, the atom ", (atomstring) "+", " is not \
  560. one of those pernicious undefined atoms. It ", (emphstring) "is", " defined. Its value is the \
  561. addition function. Here, try it:^^";
  562.  
  563. print_trans("+",
  564.  "[function]");
  565. new_line;
  566.  
  567. print "The interpreter doesn't try to actually print out the addition function, because \
  568. that's a bunch of internal program code. All functions print out looking like \
  569. ", (atomstring) "[function]", ".^^";
  570.  
  571. print_trans("(- 1 1)",
  572.  "0");
  573. print_trans("-",
  574.  "[function]");
  575. new_line;
  576.  
  577. print "You can probably guess what function ", (atomstring) "-", " evaluates to.^^";
  578.  
  579. print "Did I say that the interpreter evaluates ", (emphstring) "all", " the terms of a list? Indeed I \
  580. did. This is important. Guess what ", (atomstring) "(+ (+ 1 1) 4)", " evaluates to? Ok, it's not too \
  581. hard, but we'll go through it step by step anyway. It's a three-term list. The \
  582. first term is ", (atomstring) "+", ", which evaluates to the addition function. The second term is \
  583. the list ", (atomstring) "(+ 1 1)", ", and we've already discovered that evaluates to ", (atomstring) "2", ". The third \
  584. term is ", (atomstring) "4", ", and that evaluates to ", (atomstring) "4", ". The addition function is handed the results, \
  585. ", (atomstring) "2", " and ", (atomstring) "4", ", and guess what...^^";
  586.  
  587. print_trans("(+ (+ 1 1) 4)",
  588.  "6");
  589. new_line;
  590.  
  591. print "Actually, the addition and subtraction functions can take any number of arguments, \
  592. not just two.^^";
  593.  
  594. print_trans("(+ 1 1 4)",
  595.  "6");
  596. new_line;
  597.  
  598. print "What happens if you try to evaluate a list, and the first term doesn't evaluate \
  599. to a function? You get errors, that's what. There are a couple of ways you can \
  600. get this wrong. As your end-of-chapter exercise, meditate upon the following \
  601. exchanges:^^";
  602.  
  603. print_trans("(1 2 3 4)",
  604.  "[Error: object is not a function: 1]");
  605. print_trans("(spoggly 2 3 4)",
  606.  "[Error: undefined atom: spoggly]");
  607. new_line;
  608.  
  609. print "Oops, one more thing. The empty list -- whether you write it as ", (atomstring) "()", " or ", (atomstring) "nil", " -- \
  610. evaluates to itself. No function is called.^^";
  611.  
  612. print_trans("()",
  613.  "nil");
  614. print_trans("nil",
  615.  "nil");
  616. new_line;
  617.  
  618. ];
  619.  
  620. [ Chapter5;
  621.  
  622. print_title ("5. Quoting Expressions");
  623.  
  624. print "What's an expression which evaluates to the atom ", (atomstring) "hello", "? We know that ", (atomstring) "hello", " doesn't; \
  625. that produces an error.^^";
  626.  
  627. print_trans("hello",
  628.  "[Error: undefined atom: hello]");
  629. new_line;
  630.  
  631. print "It sure would be handy if there were a way to produce an arbitrary atom. Well, \
  632. watch:^^";
  633.  
  634. print_trans("(quote hello)",
  635.  "hello");
  636. new_line;
  637.  
  638. print (atomstring) "quote", " acts sort of like a function which returns its argument unchanged. \
  639. (Actually, it's not a function; it's a special piece of syntax. Can you see why? \
  640. It breaks a rule of functions. Answer at the end of this chapter.) You can quote \
  641. a list too:^^";
  642.  
  643. print_trans("(quote (+ 1 1))",
  644.  "(+ 1 1)");
  645. new_line;
  646.  
  647. print (atomstring) "quote", " is so useful that you can abbreviate it, by skipping the parentheses and \
  648. just writing a single quote mark.^^";
  649.  
  650. print_trans("'hello",
  651.  "hello");
  652. print_trans("'(+ 1 1)",
  653.  "(+ 1 1)");
  654. print_trans("'5",
  655.  "5");
  656. print_trans("'+",
  657.  "+");
  658. new_line;
  659.  
  660. print "That last example is important. It doesn't matter that ", (atomstring) "+", " has a value; the \
  661. expression ", (atomstring) "'+", " -- that is, ", (atomstring) "(quote +)", " -- just evaluates to ", (atomstring) "+", ".^^";
  662.  
  663. print "End of the chapter time. Why is ", (atomstring) "quote", " not a function? Because when Scheme evaluates \
  664. a function, it evaluates all the arguments before handing them in to the function. \
  665. The argument to ", (atomstring) "quote", " is ", (emphstring) "not", " evaluated; it's handed straight in, so that it can \
  666. be handed out unchanged. Watch this:^^";
  667.  
  668. print_trans("quote",
  669.  "[syntax]");
  670. new_line;
  671.  
  672. print "Special syntax forms are applied the same way functions are, but they can have \
  673. funkier effects, and they don't necessarily evaluate all their arguments. Keep track \
  674. of this fact, because someday it'll unconfuse you about something.^^";
  675.  
  676. ];
  677.  
  678. [ Chapter6;
  679.  
  680. print_title ("6. Defining Atoms");
  681.  
  682. print (atomstring) "+", " has a value which is automatically defined by the interpreter. Can we define \
  683. values for atoms ourselves? Would I ask if the answer were no? Watch this:^^";
  684.  
  685. print_trans("(define x 5)",
  686.  "5");
  687. new_line;
  688.  
  689. print (atomstring) "define", " is another piece of special syntax. It evaluates its third argument, and \
  690. assigns the resulting value to its second argument, which must be an atom. (Why can't ",
  691. (atomstring) "define", " be a function? Because all the arguments to a function are evaluated. If ", (atomstring) "define", " \
  692. tried to evaluate its second argument, it would get an undefined atom error, because \
  693. the atom hasn't been defined until ", (atomstring) "define", " defines it! Whew.)  For clarity, ", (atomstring) "define", " \
  694. returns the value it just assigned. We set ", (atomstring) "x", " to ", (atomstring) "5", "; now the expression ", (atomstring) "x", " evaluates \
  695. to ", (atomstring) "5", ".^^";
  696.  
  697. print_trans("x",
  698.  "5");
  699. print_trans("(+ x 1)",
  700.  "6");
  701. new_line;
  702.  
  703. print "We don't have to use numbers, by the way. Let's set ", (atomstring) "x", " to be ", (atomstring) "bob", ":^^";
  704.  
  705. print_trans("(define x bob)",
  706.  "[Error: undefined atom: bob]");
  707. new_line;
  708.  
  709. print "Oops -- forgot that the third value in a ", (atomstring) "define", " statement ", (emphstring) "is", " evaluated. We can't \
  710. use the ", (emphstring) "atom", " ", (atomstring) "bob", "; we need to use an expression whose ", (emphstring) "value", " is ", (atomstring) "bob", ".^^";
  711.  
  712. print_trans("(define x 'bob)",
  713.  "bob");
  714. print_trans("x",
  715.  "bob");
  716. print_trans("(+ x 1)",
  717.  "[Error: +: non-numeric argument: bob]");
  718. print_trans("'x",
  719.  "x");
  720. new_line;
  721.  
  722. print "That works. Notice that we've replaced the earlier definition of ", (atomstring) "x", " as ", (atomstring) "5", ". Also note \
  723. that addition righteously complains when we feed it an atom which isn't a number. And \
  724. also also note that ", (atomstring) "'x", " is, still and always, just plain ", (atomstring) "x", ".^^";
  725.  
  726. print "You can replace the definitions of predefined functions, too. You could do ", (atomstring) "(define + 5)", ", \
  727. for example. But I really don't recommend it. Reset the interpreter if you get carried \
  728. away with this stuff.^^";
  729.  
  730. print "Last trick of the chapter. What's going on here?^^";
  731.  
  732. print_trans("(define addify +)",
  733.  "[function]");
  734. print_trans("(addify 5 6)",
  735.  "11");
  736. new_line;
  737.  
  738. ];
  739.  
  740. [ Chapter7;
  741.  
  742. print_title ("7. List Chopping");
  743.  
  744. print "Back to lists. We often want to take them apart, see what makes them tick, and put \
  745. together new ones. For that, we'll need some tools.^^";
  746.  
  747. print "A list can be split into two parts: its first term, and its everything else. Now, \
  748. in Scheme (and Lisp), the first term is called the list's ", (emphstring) "car", ", and the everything \
  749. else is called the list's ", (emphstring) "cdr", " (rhymes with ~wooder~, more or less.) Now every \
  750. damn Lisp book in the universe explains why these things are called car and cdr, \
  751. and I'm so sick of it I'm going to leave you in the dark. Go look it up, if you \
  752. care.^^";
  753.  
  754. print "The car of ", (atomstring) "(a bb ccc)", " is ", (atomstring) "a", ". The cdr of ", (atomstring) "(a bb ccc)", " is ", (atomstring) "(bb ccc)", ". See that? The \
  755. car is the first ", (emphstring) "term", "; the cdr is the ", (emphstring) "list", " minus the first term. Important, that. \
  756. Now, this doesn't mean that the car of a list is always an atom. The car of \
  757. ", (atomstring) "((1 2) x y z)", " is ", (atomstring) "(1 2)", ". But the cdr of a list is always a list. It might be the \
  758. empty list, though. The cdr of ", (atomstring) "(hello)", " is the empty list ", (atomstring) "nil", ".^^";
  759.  
  760. print "The empty list has neither a car nor a cdr.^^";
  761.  
  762. print (atomstring) "car", " and ", (atomstring) "cdr", " are pre-defined functions in Scheme. (Ok, I'm lying -- ", (atomstring) "car", " and ", (atomstring) "cdr", " \
  763. are atoms. But they're defined to evaluate to functions, just like ", (atomstring) "+", " and ", (atomstring) "-", ". Get \
  764. over it.)^^";
  765.  
  766. print_trans("(car '(a bb ccc))",
  767.  "a");
  768. print_trans("(cdr '(a bb ccc))",
  769.  "(bb ccc)");
  770. new_line;
  771.  
  772. print "Note the quote marks. What happens if you try to evaluate ", (atomstring) "(car (a bb cc))", "? Why?^^";
  773.  
  774. print (atomstring) "car", " and ", (atomstring) "cdr", " are well-wired to complain if you try to mess with their heads:^^";
  775.  
  776. print_trans("(car 'a)",
  777.  "[Error: car: bad argument: a]");
  778. print_trans("(car '())",
  779.  "[Error: car: bad argument: nil]");
  780. new_line;
  781.  
  782. print (atomstring) "a", " isn't a list, so it can't have a car or cdr; and the empty list, as we've said, \
  783. has no car or cdr either.^^";
  784.  
  785. ];
  786.  
  787. [ Chapter8;
  788.  
  789. print_title ("8. List Constructing");
  790.  
  791. print "We takes 'em apart, we puts 'em together. If you have a car and a cdr, you can \
  792. construct a list. The ", (atomstring) "cons", " function does this.^^";
  793.  
  794. print_trans("(cons 'aaa '(bb c))",
  795.  "(aaa bb c)");
  796. print_trans("(cons 'aaa nil)",
  797.  "(aaa)");
  798. print_trans("(cons (car '(x y z z y)) (cdr '(x y z z y)))",
  799.  "(x y z z y)");
  800. new_line;
  801.  
  802. print "That last example, dreadful as it appears, just demonstrates that you can take \
  803. a single list apart into car and cdr, and reassemble it. Maybe it'd help if I \
  804. did it like this:^^";
  805.  
  806. print_trans("(define magic-word '(x y z z y))",
  807.  "(x y z z y)");
  808. print_trans("magic-word",
  809.  "(x y z z y)");
  810. print_trans("(cons (car magic-word) (cdr magic-word))",
  811.  "(x y z z y)");
  812. new_line;
  813.  
  814. print "Oh, those lovely inside-out Scheme expressions! When in doubt, break out the \
  815. magnifying lens and count parentheses.^^";
  816.  
  817. print "The cdr of a non-empty list is always a list, so the second argument you give \
  818. to ", (atomstring) "cons", " had better be a list. If you break this rule, you get a broken, twisted, \
  819. evil-twin kind of not-really-a-list, called an ~improper~ or ~dotted~ list.^^";
  820.  
  821. print_trans("(cons 'a 'b)",
  822.  "(a . b)");
  823. new_line;
  824.  
  825. print "I don't feel like explaining this right now, so just try not to do it.^^";
  826.  
  827. print "Another convenient function is ", (atomstring) "list", ", which takes a bunch of expressions and \
  828. makes a list out of them.^^";
  829.  
  830. print_trans("(list 'a 'zzz)",
  831.  "(a zzz)");
  832. print_trans("(list 'a '(1 2 3) 'end)",
  833.  "(a (1 2 3) end)");
  834. print_trans("(list)",
  835.  "nil");
  836. print_trans("(list '() (+ 4 5) '(+ 1 2) (cdr magic-word))",
  837.  "(nil 9 (+ 1 2) (y z z y))");
  838. new_line;
  839.  
  840. print "I'm being tricky with that last one. If you try it yourself, make sure you've \
  841. defined ", (atomstring) "magic-word", " the way I did a few paragraphs back. Also, see the difference \
  842. a quote can make?^^";
  843.  
  844. ];
  845.  
  846. [ Chapter9;
  847.  
  848. print_title ("9. Tests and Logic");
  849.  
  850. print "Some functions test a condition. The ", (atomstring) "=", " function, for example, tests to see if \
  851. two numbers are equal:^^";
  852.  
  853. print_trans("(= 2 2)",
  854.  "t");
  855. print_trans("(= 2 5)",
  856.  "nil");
  857. new_line;
  858.  
  859. print "As you see, the convention in Scheme is to use ", (atomstring) "nil", " to signify falsity, and \
  860. the atom ", (atomstring) "t", " to signify truth. (", (atomstring) "t", " evaluates to itself, by the way, just as ", (atomstring) "nil", " \
  861. does. More convenience; you don't have to quote ", (atomstring) "t", " when you use it.) Actually, \
  862. when a true/false value is required, you can generally supply any value; ", (atomstring) "nil", " \
  863. will be counted as false, and anything else at all will be counted as true.^^";
  864.  
  865. print "The ", (atomstring) "<", ", ", (atomstring) ">", ", ", (atomstring) "<=", ", and ", (atomstring) ">=", " functions work as you'd expect. There are also some \
  866. pre-defined functions which test other properties. ", (atomstring) "null?", " returns ", (atomstring) "t", " if its \
  867. argument is ", (atomstring) "nil", ", and ", (atomstring) "nil", " otherwise. ", (atomstring) "list?", " returns ", (atomstring) "t", " if its argument is \
  868. a list (including ", (atomstring) "nil", "), and ", (atomstring) "nil", " otherwise.^^";
  869.  
  870. print_trans("(null? nil)",
  871.  "t");
  872. print_trans("(null? t)",
  873.  "nil");
  874. print_trans("(null? 0)",
  875.  "nil");
  876. print_trans("(list? nil)",
  877.  "t");
  878. print_trans("(list? 1)",
  879.  "nil");
  880. print_trans("(list? 'a)",
  881.  "nil");
  882. print_trans("(list? '(a))",
  883.  "t");
  884. new_line;
  885.  
  886. ];
  887.  
  888. [ Chapter10;
  889.  
  890. print_title ("10. Comparisons");
  891.  
  892. print "The ", (atomstring) "=", " function compares numbers, but it produces an error if you try to \
  893. use it on atoms or lists. For that, you need the ", (atomstring) "eqv?", " and ", (atomstring) "equal?", " functions. \
  894. These are slightly different, and the difference is sort of technical and \
  895. confusing, but it's historical. You want to learn Scheme, you have to know ", (atomstring) "eqv?", " \
  896. and ", (atomstring) "equal?", " (In fact, real Scheme has ", (atomstring) "eq?", " as well, but the difference wasn't \
  897. significant in this implementation, so I left it out.)^^";
  898.  
  899. print "For atoms (including numbers), they both work as you'd expect. ", (atomstring) "nil", ", also.^^";
  900.  
  901. print_trans("(eqv? 1 2)",
  902.  "nil");
  903. print_trans("(eqv? 2 2)",
  904.  "t");
  905. print_trans("(eqv? 'one 'two)",
  906.  "nil");
  907. print_trans("(eqv? 'two 'two)",
  908.  "t");
  909. print_trans("(eqv? 2 'two)",
  910.  "nil");
  911. print_trans("(eqv? nil 'two)",
  912.  "nil");
  913. print_trans("(eqv? nil nil)",
  914.  "t");
  915. new_line;
  916.  
  917. print "(And ", (atomstring) "equal?", " would produce the same results.)^^";
  918.  
  919. print "For complex objects, such as lists and functions, things are trickier. If you \
  920. hand two complex objects to ", (atomstring) "eqv?", ", you'll get ", (atomstring) "t", " only if they both stem from the \
  921. same act of creation. (See, I told you it was confusing.)^^";
  922.  
  923. print_trans("(define greeting '(hi there))",
  924.  "(hi there)");
  925. print_trans("(define aloha (list 'hi 'there))",
  926.  "(hi there)");
  927. print_trans("(eqv? greeting greeting)",
  928.  "t");
  929. print_trans("(eqv? greeting '(hi there))",
  930.  "nil");
  931. print_trans("(eqv? greeting aloha)",
  932.  "nil");
  933. print_trans("(eqv? '(hi there) '(hi there))",
  934.  "nil");
  935. print_trans("(define hug greeting)",
  936.  "(hi there)");
  937. print_trans("(eqv? greeting hug)",
  938.  "t");
  939. print_trans("(eqv? aloha hug)",
  940.  "nil");
  941. new_line;
  942.  
  943. print "How to put this... evaluating ", (atomstring) "'(hi there)", " creates a list of two atoms. Evaluating \
  944. ", (atomstring) "(list 'hi 'there)", " creates another list of two atoms. The lists have the same \
  945. contents, but they're two separate objects. So they aren't ", (atomstring) "eqv?", " to each other. \
  946. Now, when we do ", (atomstring) "(define hug greeting)", ", we take the value of ", (atomstring) "greeting", " and \
  947. assign that very value to ", (atomstring) "hug", ", so they ", (emphstring) "are", " ", (atomstring) "eqv?", "... see? Well, maybe.^^";
  948.  
  949. print (atomstring) "equal?", ", on the other hand, works sensibly. Two lists are ", (atomstring) "equal?", " if they are \
  950. the same length and each pair of terms is ", (atomstring) "equal?", ". Given the definitions above, \
  951. you'll see that:^^";
  952.  
  953. print_trans("(equal? greeting greeting)",
  954.  "t");
  955. print_trans("(equal? greeting '(hi there))",
  956.  "t");
  957. print_trans("(equal? '(hi there) '(hi there))",
  958.  "t");
  959. print_trans("(equal? greeting aloha)",
  960.  "t");
  961. print_trans("(equal? greeting hug)",
  962.  "t");
  963. print_trans("(equal? aloha hug)",
  964.  "t");
  965. new_line;
  966.  
  967. print "What's the point of ", (atomstring) "eqv?", ", seeing how weirdly it works? It's faster. ", (atomstring) "equal?", " \
  968. has to compare every element of a list, but ", (atomstring) "eqv?", " just compares two internal \
  969. pointers.^^";
  970.  
  971. print "Up above I said that functions are as tricky as lists, when it comes to \
  972. comparison. In fact, they're trickier. If two functions stem from the same \
  973. act of creation, they're ", (atomstring) "eqv?", " and ", (atomstring) "equal?", ", just like lists. But otherwise, \
  974. two functions are never ", (atomstring) "eqv?", " or ", (atomstring) "equal?", ", even if they do the exact same thing. \
  975. (There's no good way to ", (emphstring) "tell", " if two functions do the exact same thing. I mean, \
  976. there's no way for a ", (emphstring) "person", " to tell. Not in all cases. Computers, forget it.)^^";
  977.  
  978. ];
  979.  
  980. [ Chapter11;
  981.  
  982. print_title ("11. Conditionals");
  983.  
  984. print "Scheme offers a nice assortment of conditional syntax forms. Since I'm a lazy \
  985. bum, I've only implemented the most basic one, which is ", (atomstring) "cond", ". A ", (atomstring) "cond", " structure \
  986. looks like this:^^";
  987.  
  988. print_multiatom(
  989. " (cond",
  990. "    (test1 result1)",
  991. "    (test2 result2)",
  992. "    ...",
  993. " )"
  994. );
  995. new_line;
  996.  
  997. print "I've written it on multiple lines, but that's just for clarity. The point is, \
  998. you have a list of clauses, and each clause is a list of two expressions: a \
  999. test and a result. The ", (atomstring) "cond", " syntax goes through the clauses, in order. For \
  1000. each one, it evaluates the test. If the test returns true (anything but ", (atomstring) "nil", "), \
  1001. it evaluates the result, and returns that value. If the test returns ", (atomstring) "nil", ", it \
  1002. goes on to the next clause. If all of the clauses return ", (atomstring) "nil", ", it returns ", (atomstring) "nil", ".^^";
  1003.  
  1004. print "If you're not sure what this means, look at it this way: in C, we'd write this \
  1005. as something like^^";
  1006.  
  1007. print_multiatom(
  1008. "  if (test1) return result1;",
  1009. "  else if (test2) return result2;",
  1010. "  ...",
  1011. "  else return nil;"
  1012. );
  1013. new_line;
  1014.  
  1015. print "If you want a final ~default~ clause, which will be used if all the others fail, \
  1016. you can use ", (atomstring) "(t defaultresult)", ". ", (atomstring) "t", " is always true, and that's the effect you want.^^";
  1017.  
  1018. print "You're still confused. Well, hark to the example.^^";
  1019.  
  1020. print_trans("(define val -25)",
  1021.  "-25");
  1022. print_multitrans(
  1023. "(cond",
  1024. "  ((> val 0) 'positive)",
  1025. "  ((< val 0) 'negative)",
  1026. "  (t 'zero)",
  1027. ")"
  1028. );
  1029. print_trans(2, "negative");
  1030. new_line;
  1031.  
  1032. print "The conditional tests ", (atomstring) "val", " and returns one of the atoms ", (atomstring) "positive", ", ", (atomstring) "negative", ", or \
  1033. ", (atomstring) "zero", ". (Again, we've typed it in on several lines. Notice that the interpreter \
  1034. prints a single-arrow prompt if you've started a list and not finished it yet; \
  1035. the expression won't be evaluated until you've typed it all in. As a bonus, the \
  1036. status line shows how many left parentheses are currently hanging open. Cool, \
  1037. huh?)^^";
  1038.  
  1039. ];
  1040.  
  1041. [ Chapter12;
  1042.  
  1043. print_title ("12. Creating Functions");
  1044.  
  1045. print "There'd be no point to Scheme (or Lisp) if you couldn't define your own functions. \
  1046. You get a function when you evaluate a lambda-expression. ", (atomstring) "lambda", " is another piece \
  1047. of special syntax, and here's how you use it:^^";
  1048.  
  1049. print_trans("(lambda (n) (+ n 1))",
  1050.  "[function]");
  1051. new_line;
  1052.  
  1053. print "See? A function! You can probably guess what it does, but let's check:^^";
  1054.  
  1055. print_trans("(define fred (lambda (n) (+ n 1)))",
  1056.  "[function]");
  1057. print_trans("(fred 56)",
  1058.  "57");
  1059. new_line;
  1060.  
  1061. print "First we define ", (atomstring) "fred", " to be our new function, and then we call it with ", (atomstring) "56", " as the \
  1062. argument. You don't need the definition, by the way. ", (atomstring) "(lambda (n) (+ n 1))", " \
  1063. evaluates to a function, so you can use it as the first term of a list, just like \
  1064. ", (atomstring) "+", " or ", (atomstring) "car", ":^^";
  1065.  
  1066. print_trans("((lambda (n) (+ n 1)) 56)",
  1067.  "57");
  1068. new_line;
  1069.  
  1070. print "It's a little hard to read, but count the parentheses and you'll see how it works.^^";
  1071.  
  1072. print "Time to be more specific. The ", (atomstring) "lambda", " syntax takes two arguments. The first must \
  1073. be a list of atoms, which are the names of the arguments of the function. The \
  1074. second is an expression which is evaluated to produce the function result.^^";
  1075.  
  1076. print "So when we call our little one-argument function, it's ", (emphstring) "kind", " of like we did the \
  1077. following:^^";
  1078.  
  1079. print_trans("(define n 56)",
  1080.  "56");
  1081. print_trans("(+ n 1)",
  1082.  "57");
  1083. new_line;
  1084.  
  1085. print "Only, not really. Function argument definitions are local, not global. The assignment \
  1086. of ", (atomstring) "56", " to ", (atomstring) "n", " is only visible ", (emphstring) "to the function", ". In the outside world, the real world, \
  1087. ", (atomstring) "n", " isn't affected at all.^^";
  1088.  
  1089. print_trans("(define n 11)",
  1090.  "11");
  1091. print_trans("(fred 93)",
  1092.  "94");
  1093. print_trans("n",
  1094.  "11");
  1095. new_line;
  1096.  
  1097. print "This is important. It's called static binding. Comp Sci types think it's really cool. \
  1098. It means that functions are all wrapped up in themselves -- they can't have side \
  1099. effects, and they can't be affected by outside influences (besides their arguments, \
  1100. of course.) Um, mostly. If you're careful. We'll get back to this, I hope.^^";
  1101.  
  1102. print "A function can have any number of arguments, including zero:^^";
  1103.  
  1104. print_trans("(define greeter (lambda () 'hello))",
  1105.  "[function]");
  1106. print_trans("(greeter)",
  1107.  "hello");
  1108. print_trans("(greeter 5)",
  1109.  "[Error: too many arguments to function]");
  1110. new_line;
  1111.  
  1112. print "You can also have a function with a variable number of arguments. (Remember ", (atomstring) "+", "?) \
  1113. You do this by giving an atom as the second argument to ", (atomstring) "lambda", ", instead of a list \
  1114. of atoms. The whole list of arguments (possibly empty) gets assigned to the atom, \
  1115. inside the function.^^";
  1116.  
  1117. print_trans("(define prefix-foo (lambda args (cons 'foo args)))",
  1118.  "[function]");
  1119. print_trans("(prefix-foo 5)",
  1120.  "(foo 5)");
  1121. print_trans("(prefix-foo 'a 'bb 'ccc)",
  1122.  "(foo a bb ccc)");
  1123. print_trans("(prefix-foo)",
  1124.  "(foo)");
  1125. new_line;
  1126.  
  1127. ];
  1128.  
  1129. [ Chapter13;
  1130.  
  1131. print_title ("13. Fun With Recursion");
  1132.  
  1133. print "How shall we define recursion? The old (old, old) joke is ~Recursion: See recursion.~ \
  1134. This is a stinking lie. The correct definition is ~Recursion: If you already know \
  1135. what recursion is, just remember the answer. Otherwise, find someone who is standing \
  1136. closer to Douglas Hofstadter than you are; then ask him or her what recursion is.~^^";
  1137.  
  1138. print "(That's original with me, folks, so attribute it if you quote it. :-)^^";
  1139.  
  1140. print "The idea is that you handle the very simplest case directly. For more complex cases, \
  1141. you chop off the littlest toe of the problem, handle that bit, and call yourself on \
  1142. the remaining nearly-as-big problem... because you know you can handle it. Because \
  1143. you know you can handle the slightly-smaller-than-that problem. Because... eventually, \
  1144. because you know you can handle the very simplest case. In math, your teacher called \
  1145. this ~proof by induction.~^^";
  1146.  
  1147. print "Scheme ", (emphstring) "loves", " this stuff. Look at the car and cdr stuff; they're designed to split \
  1148. a list into the first bit and the remaining nearly-as-big bit. Perfect! Let's use this \
  1149. to define a function which finds the ", (emphstring) "last", " term in a list.^^";
  1150.  
  1151. print_multitrans(
  1152. "(define last (lambda (ls)",
  1153. "   (cond",
  1154. "     ((null? (cdr ls)) (car ls))",
  1155. "     (t (last (cdr ls)))",
  1156. ")))"
  1157. );
  1158. new_line;
  1159.  
  1160. print "Well, that's a bargeload of parentheses, isn't it. Let's sort through it. We define \
  1161. ", (atomstring) "last", " to be a function, that is, the result of a lambda-expression. This function \
  1162. takes one argument, ", (atomstring) "ls", ". It consists of a ", (atomstring) "cond", " expression. First clause: if \
  1163. ", (atomstring) "(cdr ls)", " is ", (atomstring) "null", "?, then return ", (atomstring) "(car ls)", ". Otherwise, return ", (atomstring) "(last (cdr ls))", ". \
  1164. That's all.^^";
  1165.  
  1166. print "Got it yet? The idea is this: if you have a one-term list, the last term is the \
  1167. first term. You can check this by seeing if ", (atomstring) "(cdr ls)", " is ", (atomstring) "nil", ", because only in a \
  1168. one-term list is the cdr empty. So if ", (atomstring) "(null? (cdr ls))", ", we should return the first \
  1169. term in the list, which is ", (atomstring) "(car ls)", ". Otherwise, we have a list which is two terms or \
  1170. more -- so we can find its last element by calling ", (atomstring) "last", " on its cdr! It's not an \
  1171. infinite loop, because the cdr of ", (atomstring) "ls", " is shorter than ", (atomstring) "ls", " is.^^";
  1172.  
  1173. print_trans("(last '(a))",
  1174.  "a");
  1175. print_trans("(last '(a bb))",
  1176.  "bb");
  1177. print_trans("(last '(a bb c))",
  1178.  "c");
  1179. print_trans("(last '(a bb c (xx)))",
  1180.  "(xx)");
  1181. new_line;
  1182.  
  1183. print "And lo, it works.^^";
  1184.  
  1185. ];
  1186.  
  1187. [ Chapter14;
  1188.  
  1189. print_title ("14. Local Definitions With Let");
  1190.  
  1191. print "You often want to define temporary values -- helper functions, or temporary storage \
  1192. for partially-computed values, or whatever. Scheme allows you to do this with the \
  1193. ", (atomstring) "let", " syntax, and a few related ones.^^";
  1194.  
  1195. print_multiatom(
  1196. " (let",
  1197. "    (",
  1198. "      (atom1 value1)",
  1199. "      (atom2 value2)"
  1200. );
  1201. print_multiatom(
  1202. "      ...",
  1203. "    )",
  1204. "    result",
  1205. " )"
  1206. );
  1207. new_line;
  1208.  
  1209. print "What goes on here is this: First, each of the value expressions is evaluated. Then \
  1210. a local binding is made, with each value assigned to its atom. Then the result \
  1211. expression is evaluated, with those assignments in place. The local assignments \
  1212. are thrown away, and the value of result is returned.^^";
  1213.  
  1214. print "This sort of temporary assignment is exactly like what happens with function arguments. \
  1215. The definitions are only visible to the result expression -- not in the outside world. \
  1216. In fact, you can rewrite a ", (atomstring) "let", " expression as a function definition and call:^^";
  1217.  
  1218. print_multiatom(
  1219. " ((lambda (atom1 atom2 ...) result)  (value1 value2 ...))"
  1220. );
  1221. new_line;
  1222.  
  1223. print "But the ", (atomstring) "let", " syntax is easier to read. Example time...^^";
  1224.  
  1225. print_multitrans(
  1226. "(let",
  1227. "    ((a 1) (b 2))",
  1228. "  (+ a b)",
  1229. ")"
  1230. );
  1231. print_trans(2, "3");
  1232. print_multitrans(
  1233. "(let",
  1234. "    ((func car))",
  1235. "  (func '(a b c))",
  1236. ")"
  1237. );
  1238. print_trans(2, "a");
  1239. print_multitrans(
  1240. "(let",
  1241. "    ((cost '(nickel dime)))",
  1242. "  (eqv? cost cost)",
  1243. ")"
  1244. );
  1245. print_trans(2, "t");
  1246. print_trans("a",
  1247.  "[Error: undefined atom: a]");
  1248. print_trans("func",
  1249.  "[Error: undefined atom: func]");
  1250. print_trans("cost",
  1251.  "[Error: undefined atom: cost]");
  1252. new_line;
  1253.  
  1254. print "It's important to understand that ", (emphstring) "all", " the values in a ", (atomstring) "let", " are evaluated before ", 
  1255. (emphstring) "any", " of the assignments are made. More correctly, none of the local assignments are \
  1256. visible to the value expressions; they're only visible to the result expression. If you \
  1257. want to make several definitions that refer to each other, you could use nested ", (atomstring) "let", " \
  1258. statements. It's easier to use the ", (atomstring) "let*", " syntax, however. ", (atomstring) "let*", " is just like ", (atomstring) "let", ", \
  1259. except that the assignments are made in order, and each one is visible to all the \
  1260. values after it.^^";
  1261.  
  1262. print_multitrans(
  1263. "(let*",
  1264. "  ((a 1)  (b (+ a 1)))",
  1265. "  b",
  1266. ")"
  1267. );
  1268. print_trans(2, "2");
  1269. new_line;
  1270.  
  1271. print "If you tried that with ", (atomstring) "let", ", you'd get an ~undefined atom: a", "~ error, because ", (atomstring) "a", " \
  1272. isn't defined at the point where ", (atomstring) "(+ a 1)", " is evaluated.^^";
  1273.  
  1274. ];
  1275.  
  1276. [ Chapter15;
  1277.  
  1278. print_title ("15. Recursion, Functions, Endless Fun");
  1279.  
  1280. print (atomstring) "let*", " is cool, but it doesn't allow you to do really funky recursive stuff, with \
  1281. several definitions that ", (emphstring) "really", " all reference each other. For that, you need \
  1282. ", (atomstring) "letrec", ". ", (atomstring) "letrec", " has the same form as ", (atomstring) "let", " and ", (atomstring) "let*", ", but any of the assigned \
  1283. values can use any of the other atoms being bound. Sort of. The catch is, the \
  1284. atoms being bound can only be used ", (emphstring) "inside lambda-expressions.", " So this isn't \
  1285. legal:^^";
  1286.  
  1287. print_multitrans(
  1288. "(letrec",
  1289. "  ((a a))",
  1290. "  a",
  1291. ")"
  1292. );
  1293. new_line;
  1294.  
  1295. print "This is bad because the ", (emphstring) "use", " of the atom being defined (the second ", (atomstring) "a", ", that \
  1296. is) isn't ~protected~ inside a lambda-expression. If you think this is an \
  1297. arbitrary restriction, consider: if it were legal, what the heck would it \
  1298. evaluate to?^^";
  1299.  
  1300. print "In case you were about to try this, by the way -- yes, I see you in the corner \
  1301. -- you'll find it doesn't produce an error; it returns ", (atomstring) "nil", ". If there were \
  1302. more terms being defined in the ", (atomstring) "letrec", ", the results could be even stranger. \
  1303. This is because I used a fairly unpleasant hack when writing the ", (atomstring) "letrec", " \
  1304. code. (A legal hack, honest. The Scheme standard says that this sort of \
  1305. ", (atomstring) "letrec", " abuse produces undefined results.)^^";
  1306.  
  1307. print "So how ", (emphstring) "can", " ", (atomstring) "letrec", " be used? Well, the following is legal:^^";
  1308.  
  1309. print_multitrans(
  1310. "(letrec",
  1311. "  ((a (lambda () a)))",
  1312. "  a",
  1313. ")"
  1314. );
  1315. new_line;
  1316.  
  1317. print "The assignment value is ", (atomstring) "(lambda () a)", ", which only uses ", (atomstring) "a", " inside the \
  1318. lambda-expression. (The final term of the ", (atomstring) "letrec", ", which in this case is ", (atomstring) "a", ", \
  1319. is allowed to use all the defined atoms -- they've all been defined by that \
  1320. time.) What does ", (emphstring) "this", " do? Let's see:^^";
  1321.  
  1322. print_multitrans(
  1323. "(define thing",
  1324. "  (letrec",
  1325. "    ((a (lambda () a)))",
  1326. "    a",
  1327. "  )",
  1328. ")"
  1329. );
  1330. print_trans(2, "[function]");
  1331. new_line;
  1332.  
  1333. print "Okay, ", (atomstring) "thing", " has been defined to be a function. What function is this? It's the \
  1334. function which the ", (atomstring) "letrec", " statement temporarily defined to be ", (atomstring) "a", ". What was ", (atomstring) "a", " \
  1335. defined as? A function which takes no arguments, and returns whatever ", (atomstring) "a", " was \
  1336. defined as.^^";
  1337.  
  1338. print "In other words, this is everyone's favorite twisted example: the function which \
  1339. returns ", (emphstring) "itself", ". Let's check that:^^";
  1340.  
  1341. print_trans("thing",
  1342.  "[function]");
  1343. print_trans("(thing)",
  1344.  "[function]");
  1345. print_trans("((thing))",
  1346.  "[function]");
  1347. print_trans("(eqv? thing (thing))",
  1348.  "t");
  1349. new_line;
  1350.  
  1351. print "Even ", (atomstring) "eqv?", " agrees: the function assigned to ", (atomstring) "thing", " is the very same function \
  1352. returned by evaluating ", (atomstring) "(thing)", ", which is to say, the result of calling the \
  1353. function assigned to ", (atomstring) "thing", ". (Notice that in this chapter, I'm being careful \
  1354. to distinguish the value assigned to ", (atomstring) "thing", " from the atom ", (atomstring) "thing", " itself. The \
  1355. function doesn't return an atom; it returns a function.)^^";
  1356.  
  1357. print "What would happen if we tried this with ", (atomstring) "let", " instead of ", (atomstring) "letrec", "? Go ahead, \
  1358. try it.^^";
  1359.  
  1360. print_multitrans(
  1361. "(define thing",
  1362. "  (let",
  1363. "    ((a (lambda () a)))",
  1364. "    a",
  1365. "  )",
  1366. ")"
  1367. );
  1368. print_trans(2, "[function]");
  1369. print_trans("(thing)",
  1370.  "[Error: undefined atom: a]");
  1371. new_line;
  1372.  
  1373. print "Like we said, all the values in a ", (atomstring) "let", " are evaluated before any of the \
  1374. assignments are made. So that lambda-expression is evaluated, producing a \
  1375. function which returns whatever is assigned to ", (atomstring) "a", ". But at this point, nothing \
  1376. ", (emphstring) "has", " been assigned to ", (atomstring) "a", " yet. And -- remember static binding -- functions \
  1377. are all wrapped up in themselves. The function can't see the temporary \
  1378. assignment to ", (atomstring) "a", " which is made later on. That assignment only exists within \
  1379. the scope of the ", (atomstring) "let", " statement. You can do it with ", (atomstring) "letrec", ", because all the \
  1380. assignments in a ", (atomstring) "letrec", " exist within each other's scope. (Although they're \
  1381. incomplete, in a funny sense, which is why they have to be protected in a \
  1382. function.)^^";
  1383.  
  1384. ];
  1385.  
  1386. [ Chapter16;
  1387.  
  1388. print_title ("16. Scope");
  1389.  
  1390. print "Oops, I started talking about scope. Time to define it.^^";
  1391.  
  1392. print "All of the local assignments in a function -- its arguments, and any \
  1393. assignments made by ", (atomstring) "let", " and variants -- are fixed at the point where the \
  1394. function was defined. That's what ~static~ means. Look at the position of the \
  1395. lambda expression, see what ", (atomstring) "let", " statements it's inside, and you can tell what \
  1396. assignments it knows about. That's the function's scope.^^";
  1397.  
  1398. print "Top-level definitions -- those created with ", (atomstring) "define", " -- are different. \
  1399. They're visible everywhere. They can also change at any time. Convenient, \
  1400. but possibly a source of bugs.^^";
  1401.  
  1402. print "Best to illustrate the difference with an example. Can't you define the evil \
  1403. function that returns itself more simply, this way?^^";
  1404.  
  1405. print_multitrans(
  1406. "(define selfer",
  1407. "  (lambda () selfer)",
  1408. ")"
  1409. );
  1410. print_trans(2, "[function]");
  1411. new_line;
  1412.  
  1413. print "Well, yes, that works. But it's dependent on the global definition of ", (atomstring) "selfer", ". \
  1414. If you break that, the function stops working.^^";
  1415.  
  1416. print_trans("(define another-selfer selfer)",
  1417.  "[function]");
  1418. print_trans("(define selfer 'toast)",
  1419.  "toast");
  1420. print_trans("(another-selfer)",
  1421.  "toast");
  1422. print_trans("(eqv? another-selfer (another-selfer))",
  1423.  "nil");
  1424. new_line;
  1425.  
  1426. print "The ", (atomstring) "thing", " function defined in the previous chapter will always keep working, \
  1427. even if we assigned it to ", (atomstring) "another-thing", " and changed the definition of ", (atomstring) "thing", ". \
  1428. If a function doesn't rely on top-level definitions that might change, its \
  1429. behavior is completely predictable. This is generally a good thing.^^";
  1430.  
  1431. print "On the other hand, a function that does rely on top-level definitions can be \
  1432. affected by other functions that change that definition. This sort of thing is \
  1433. called a side effect; doing one thing has a side effect which affects another \
  1434. thing. In functional programming, people say they hate side effects, but actually \
  1435. it's hard to break the habit of using them. (Imperative languages like Pascal \
  1436. and C are ", (emphstring) "made", " of side effects. Every time you change the value of a variable, \
  1437. you affect everything else that uses that variable.)^^";
  1438.  
  1439. ];
  1440.  
  1441. [ Chapter17;
  1442.  
  1443. print_title ("17. Return");
  1444.  
  1445. print "Well, that's it for the manual. We haven't covered all of Scheme by any means, \
  1446. but we've gone through all the foundations. If you've been following along with \
  1447. the genie's exercises, you have a handle on how to think in Scheme.^^";
  1448.  
  1449. print "The definitive reference book on Scheme is ", (emphstring) "The Scheme Programming Language,", 
  1450. " by R. Kent Dybvig. (No, I have no idea. I can't think of a color which starts \
  1451. with D.) Pick it up, and find a real Scheme interpreter, if you're interested \
  1452. in learning more. If you ever figure out how continuations work, please come and \
  1453. explain them to me.^^";
  1454.  
  1455. print "If it crosses your path of life to learn Lisp, you'll find that it's pretty much \
  1456. what you've learned here; just a little messier. (The biggest difference is that \
  1457. atoms have two distinct values assigned to them -- a data value, and a function \
  1458. value. I've never understood why. It's just something to remember.)^^";
  1459.  
  1460. print "If you think this whole thing is a waste of your time... then why did you read \
  1461. this far?^^";
  1462.  
  1463. print "Have fun.^^";
  1464.  
  1465. ];
  1466.  
  1467. [ Chapter18;
  1468.  
  1469. print_title ("18. Reference: Functions");
  1470.  
  1471. print "This is a list of all pre-defined functions. Some of them have more functionality \
  1472. than the tutorial describes, so listen up.^^";
  1473.  
  1474. print (atomstring) "(car v)", " : 1 argument (a non-empty list)^";
  1475. print "Returns the first term of ", (atomstring) "v", ".^^";
  1476.  
  1477. print (atomstring) "(cdr v)", " : 1 argument (a non-empty list)^";
  1478. print "Returns the list containing all but the first term of ", (atomstring) "v", ".^^";
  1479.  
  1480. print (atomstring) "(cons v w)", " : 2 arguments (the second a list)^";
  1481. print "Returns the list whose first term is ", (atomstring) "v", " and the rest of whose terms are \
  1482. the terms of ", (atomstring) "w", ".^^";
  1483.  
  1484. print (atomstring) "(length v)", " : 1 argument (a list)^";
  1485. print "Returns the number of terms in ", (atomstring) "v", ".^^";
  1486.  
  1487. print (atomstring) "(list v ...)", " : 0 or more arguments^";
  1488. print "Returns the list whose terms are the given arguments.^^";
  1489.  
  1490. print (atomstring) "(not v)", " : 1 argument^";
  1491. print "Returns ", (atomstring) "t", " if ", (atomstring) "v", " is ", (atomstring) "nil", ", and ", (atomstring) "nil", " otherwise.^^";
  1492.  
  1493. print (atomstring) "(eqv? v w)", " : 2 arguments^";
  1494. print "Returns ", (atomstring) "t", " if ", (atomstring) "v", " and ", (atomstring) "w", " are both ", (atomstring) "nil", ", or are the same atom, or were created at \
  1495. the same time. Returns ", (atomstring) "nil", " otherwise.^^";
  1496.  
  1497. print (atomstring) "(equal? v w)", " : 2 arguments^";
  1498. print "Returns ", (atomstring) "t", " if ", (atomstring) "v", " and ", (atomstring) "w", " are ", (atomstring) "eqv?", ", or are lists of the same length all of whose \
  1499. terms are ", (atomstring) "equal?", ".^^";
  1500.  
  1501. print (atomstring) "(null? v)", " : 1 argument^";
  1502. print "Returns ", (atomstring) "t", " if ", (atomstring) "v", " is ", (atomstring) "nil", ", and ", (atomstring) "nil", " otherwise. (Yes, this is the same as ", (atomstring) "not", ".)^^";
  1503.  
  1504. print (atomstring) "(list? v)", " : 1 argument^";
  1505. print "Returns ", (atomstring) "t", " if ", (atomstring) "v", " is a list, including ", (atomstring) "nil", ". Returns ", (atomstring) "nil", " if ", (atomstring) "v", " is anything \
  1506. else, such as an atom or function.^^";
  1507.  
  1508. print (atomstring) "(= v ...)", " : 1 or more arguments (all numbers)^";
  1509. print "Returns ", (atomstring) "t", " if all the arguments are the same number. If there is only one \
  1510. argument, always returns ", (atomstring) "t", ".^^";
  1511.  
  1512. print (atomstring) "(> v ...)", " : 1 or more arguments (all numbers)^";
  1513. print "Returns ", (atomstring) "t", " if all the arguments are numbers in strictly descending sequence. \
  1514. Otherwise returns ", (atomstring) "nil", ". If there is only one argument, always returns ", (atomstring) "t", ".^^";
  1515.  
  1516. print (atomstring) "(>= v ...)", " : 1 or more arguments (all numbers)^";
  1517. print "Returns ", (atomstring) "t", " if all the arguments are numbers in descending sequence, not necessarily \
  1518. strictly. Otherwise returns ", (atomstring) "nil", ". If there is only one argument, always returns ", (atomstring) "t", ".^^";
  1519.  
  1520. print (atomstring) "(< v ...)", " : 1 or more arguments (all numbers)^";
  1521. print "Returns ", (atomstring) "t", " if all the arguments are numbers in strictly ascending sequence. \
  1522. Otherwise returns ", (atomstring) "nil", ". If there is only one argument, always returns ", (atomstring) "t", ".^^";
  1523.  
  1524. print (atomstring) "(<= v ...)", " : 1 or more arguments (all numbers)^";
  1525. print "Returns ", (atomstring) "t", " if all the arguments are numbers in ascending sequence, not necessarily \
  1526. strictly. Otherwise returns ", (atomstring) "nil", ". If there is only one argument, always returns ", (atomstring) "t", ".^^";
  1527.  
  1528. print (atomstring) "(+ v ...)", " : 0 or more arguments (all numbers)^";
  1529. print "Returns the sum of all the arguments. If there are no arguments, returns ", (atomstring) "0", ".^^";
  1530.  
  1531. print (atomstring) "(- v ...)", " : 0 or more arguments (all numbers)^";
  1532. print "Returns the first argument minus the sum of all the other arguments. \
  1533. If there is only one argument, returns its negative. If there are no arguments, \
  1534. returns ", (atomstring) "0", ".^^";
  1535.  
  1536. print (atomstring) "(eval v)", " : 1 argument^";
  1537. print "Returns the result of evaluating ", (atomstring) "v", ". (Note that since ", (atomstring) "eval", " is a function, \
  1538. whatever you give as the argument is evaluated before it is handed in. So \
  1539. ", (atomstring) "eval", " sort of double-evaluates whatever you give it.)^^";
  1540.  
  1541. ];
  1542.  
  1543. [ Chapter19;
  1544.  
  1545. print_title ("19. Reference: Syntactic Forms");
  1546.  
  1547. print "This is a list of all the special syntax forms available.^^";
  1548.  
  1549. print (atomstring) "(quote v)", " : 1 argument^";
  1550. print "Returns ", (atomstring) "v", ", without evaluating it at all.^^";
  1551.  
  1552. print (atomstring) "(error ...)", " : any number of arguments^";
  1553. print "Causes an error. The arguments are ignored. This aborts the evaluation of an \
  1554. expression; once any part causes an error, the entire thing results in an error.^^";
  1555.  
  1556. print (atomstring) "(cond clause1 ...)", " : any number of clauses; each clause is a list of either one \
  1557. or two terms^";
  1558. print "Goes through the clauses, in order. If the first (or only) term of a clause \
  1559. evaluates to ", (atomstring) "nil", ", it is skipped and the next one tested. The leftmost clause whose \
  1560. first term evaluates to non-", (atomstring) "nil", " is the winner. If it has only one term, that \
  1561. non-", (atomstring) "nil", " value is returned. If it has two, the result of evaluating the second \
  1562. term is returned. If no clause is a winner, ", (atomstring) "nil", " is returned.^^";
  1563.  
  1564. print (atomstring) "(define atom v)", " : two arguments; the first an atom^";
  1565. print "The result of evaluating ", (atomstring) "v", " is assigned to ", (atomstring) "atom", " (a top-level definition). If \
  1566. ", (atomstring) "atom", " already has a top-level definition, the older definition is replaced. \
  1567. The new value is also returned.^^";
  1568.  
  1569. print (atomstring) "(lambda arglist v)", " : two arguments^";
  1570. print "Returns a function. The scope of the function is the scope in which the \
  1571. lambda-expression is evaluated to produce it. When a function is called, the arguments \
  1572. it is given are assigned to the atoms in ", (atomstring) "arglist", ", producing a new scope on top \
  1573. of the function's scope; ", (atomstring) "v", " is then evaluated in this new scope. ", (atomstring) "arglist", " may \
  1574. be a single atom (in which case all the function's arguments are put into a list \
  1575. which is assigned to that atom), or ", (atomstring) "nil", " (in which case the function takes zero \
  1576. arguments), or a list of atoms (in which case the function takes that many \
  1577. arguments.)^^";
  1578.  
  1579. print (atomstring) "(let ((atom1 def1) ...) v)", " : two arguments; the first is a list of clauses; each \
  1580. clause is a list of two terms^";
  1581. print "All the definitions in the list of clauses are evaluated, in the current scope. \
  1582. Then a new scope is created, in which those values are assigned to their respective \
  1583. atoms (a local or temporary definition.) ", (atomstring) "v", " is evaluated in this new scope, and \
  1584. the result is returned.^^";
  1585.  
  1586. print (atomstring) "(let* ((atom1 def1) ...) v)", " : two arguments; the first is a list of clauses; each \
  1587. clause is a list of two terms^";
  1588. print "In the current scope, ", (atomstring) "def1", " is evaluated. A new scope is created in which \
  1589. the resulting value is assigned to ", (atomstring) "atom1", ". In this new scope, ", (atomstring) "def2", " is evaluated. \
  1590. A newer scope is created in which the resulting value is assigned to ", (atomstring) "atom2", ". This \
  1591. continues until all clauses are handled. ", (atomstring) "v", " is evaluated in the final scope, and \
  1592. the result is returned.^^";
  1593.  
  1594. print (atomstring) "(letrec ((atom1 def1) ...) v)", " : two arguments; the first is a list of clauses; each \
  1595. clause is a list of two terms^";
  1596. print "A new scope is created in which the atoms of all the clauses are assigned undefined \
  1597. values. All the definitions of the clauses are then evaluated, in this new scope. \
  1598. (For the results to be valid, all uses of the atoms must be inside lambda-expressions.) \
  1599. The resulting values are written into the scope, completing it, and then ", (atomstring) "v", " is \
  1600. evaluated in the scope.^^";
  1601.  
  1602. ];
  1603.  
  1604. [ Chapter20;
  1605.  
  1606. print_title ("20. Reference: Improper Lists");
  1607.  
  1608. print "And finally, I have been convinced to put in more about improper lists. (Chapter \
  1609. 8 was where I said that I didn't feel like explaining them.) This section is tacked \
  1610. on as reference material because you don't really need to know about improper lists \
  1611. for the purposes of this tutorial, but you're undoubtedly going to stumble into \
  1612. them anyway. So you can think of this chapter as an appendix. A weird little \
  1613. continuation tacked on after the manual's full stop. Ha! I just kill myself sometimes. \
  1614. Or at least strain my back reaching after feeble jokes.^^";
  1615.  
  1616. print "An improper list, or dotted list, is just what you get when the cdr of a list is \
  1617. not a list. That is, if the second argument of a ", (atomstring) "cons", " call is not a list, the \
  1618. result of the ", (atomstring) "cons", " will be an improper list.^^";
  1619.  
  1620. print "You can also create an improper list by typing the dotted form itself.^^";
  1621.  
  1622. print_trans("'(a . b)",
  1623.  "(a . b)");
  1624. new_line;
  1625.  
  1626. print "If the second argument of a ", (atomstring) "cons", " call is an improper list, the result will be a \
  1627. longer improper list.^^";
  1628.  
  1629. print_trans("(cons 'z '(a . b))",
  1630.  "(z a . b)");
  1631. print_trans("(cons 'rats '(z a . b))",
  1632.  "(rats z a . b)");
  1633. new_line;
  1634.  
  1635. print "There can only be one dot in an improper list, and it will always be just before \
  1636. the last term. Why? Well, in a proper list, the cdr is either a non-empty list \
  1637. (meaning there's more to come) or the empty list (meaning you've reached the \
  1638. end.) In an improper list, the cdr is a non-list, meaning you've reached a \
  1639. strange sort of appendix; but you can't go on after that, because the appendix \
  1640. ", (emphstring) "isn't", " a list, it's just one thing; so there's no more to do. The appendix is \
  1641. written after the dot, and then you're done.^^";
  1642.  
  1643. print "Of course, if the appendix ", (emphstring) "is", " a list, then you're not writing an improper \
  1644. list at all. This follows directly from the rules, and a little experimentation \
  1645. shows that it's true:^^";
  1646.  
  1647. print_trans("'(a . (b c))",
  1648.  "(a b c)");
  1649. new_line;
  1650.  
  1651. print "An improper list isn't actually that awful; ", (atomstring) "list?", " will say that it is a list, \
  1652. and you can do anything with it that you can do with a proper list. The only \
  1653. problem is that if you take its cdr, and assume the result is a list, you will \
  1654. get an ugly surprise. Many Scheme functions (including some built-in ones) do \
  1655. make this assumption, and they will choke horribly when fed improper lists. \
  1656. However, if you want to use improper lists for your own purposes, there's no \
  1657. reason not to.^^";
  1658.  
  1659. print (emphstring) "Now", " we're done.^^";
  1660.  
  1661. ];
  1662.